package com.naiterui.ehp.bs.patient.service.message.impl;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.bo.emr.InquireCaseBO;
import com.naiterui.ehp.bp.bo.im.PatientMsgSendParamBO;
import com.naiterui.ehp.bp.bo.patient.MsgMaPublishBatchParamBO;
import com.naiterui.ehp.bp.bo.patient.MsgMaPublishParamBO;
import com.naiterui.ehp.bp.bo.patient.MsgPublishBO;
import com.naiterui.ehp.bp.bo.patient.MsgPublishBatchParamBO;
import com.naiterui.ehp.bp.bo.patient.MsgPublishParamBO;
import com.naiterui.ehp.bp.bo.recommend.PatientDiagnisisBO;
import com.naiterui.ehp.bp.bo.subscribe.InquiryRemindBO;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.Hospital;
import com.naiterui.ehp.bp.domain.Patient;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.event.EventUtil;
import com.naiterui.ehp.bs.patient.bo.notice.FollowupMsg;
import com.naiterui.ehp.bs.patient.dao.IDoctorDao;
import com.naiterui.ehp.bs.patient.dao.IHospitalDao;
import com.naiterui.ehp.bs.patient.dao.IPatientDao;
import com.naiterui.ehp.bs.patient.exception.ExceptionCodes;
import com.naiterui.ehp.bs.patient.feign.EmrFeginClient;
import com.naiterui.ehp.bs.patient.feign.RecomFeginClient;
import com.naiterui.ehp.bs.patient.feign.WxFeignClient;
import com.naiterui.ehp.bs.patient.handler.data.WxMaMsgData;
import com.naiterui.ehp.bs.patient.handler.data.WxMaMsgEvent;
import com.naiterui.ehp.bs.patient.handler.data.WxMsgEvent;
import com.naiterui.ehp.bs.patient.service.ITemplateNoticeService;
import com.naiterui.ehp.bs.patient.service.message.IMessageSendService;
import com.naiterui.ehp.bs.patient.utils.TitleUtil;
import com.naiterui.ehp.bs.patient.utils.message.MessagePlateformFactory;
import com.naiterui.ehp.bs.patient.utils.message.MessageTemplate;
import com.naiterui.ehp.bs.patient.vo.message.MessageVo;
import com.naiterui.ehp.bs.wechat.service.ICustomMsgApiService;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @Date:2018/11/1
 * @Time:10:22
 * @Version:V1.0
 */
@Slf4j
@Service
@AllArgsConstructor
public class ApMessageSendServiceImpl implements IMessageSendService {

    private final IDoctorDao doctorDao;
    private final IPatientDao patientDao;
    private final IHospitalDao hospitalDao;
    private final EmrFeginClient emrFeginClient;
    private final ITemplateNoticeService templateNoticeService;
    private final ICustomMsgApiService customMsgApiService;
    private final RecomFeginClient recomFeginClient;
    private final WxFeignClient wxFeignClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer sendMessage(MessageVo messageVo) {
        int code = 0;
        MessageTemplate messageTemplate = MessagePlateformFactory.getMessage(messageVo.getPlatformId());
        String json = JSONObject.toJSONString(messageVo);
        String paramData = JSONObject.parseObject(json).getString("paramData");
        Integer templateId = Integer.valueOf(JSONObject.parseObject(json).getString("templateId"));
        code = messageTemplate.send(paramData, templateId);
        return code;
    }

    @Override
    public MsgPublishBO publishMessage(MsgPublishParamBO publishParamBO) {

//        Doctor doctor = doctorDao.get(publishParamBO.getDoctorId());
//        Patient patient = patientDao.get(publishParamBO.getPatientId());
//
//        if (patient == null || doctor == null) {
//            return MsgPublishBO.builder().success(false).build();
//        }

        //客服消息是否激活校验
//        boolean onActive = RedisUtil.keyOps().existsKey(CommonConstant.CONSULT_PATIENT_ACTIVE + patient.getOpenId());

        //医生医院信息（客服消息不可使用，模板消息推送时使用）
//        String hospitalName = null;
//        if (doctor.getHospitalId() != null) {
//            Hospital hospital = hospitalDao.get(doctor.getHospitalId());
//            doctor.getHospitalName();
//            hospitalName = hospital != null ? hospital.getName() : doctor.getHospitalName();
//        }
//        String doctorFullName = doctor.getName() +
//                (doctor.getTitleId() == null ? "" : "-" + TitleUtil.getTitle(doctor.getTitleId())) +
//                (StringUtils.isBlank(hospitalName) ? "" : "-" + hospitalName);
//        String doctorFullName = doctor.getName() + (doctor.getTitleId() == null ? "" : "-" + TitleUtil.getTitle(doctor.getTitleId()));

//        EventUtil.publishEvent(new WxMaMsgEvent(publishParamBO, WxMaMsgData
//                .builder()
//                .content(publishParamBO.getContent())
//                .doctorId(publishParamBO.getDoctorId())
//                .doctorName(doctorFullName)
//                .patientName(Optional.ofNullable(patient.getName()).map(o -> patient.getNickName()).orElse("患者名称"))
//                .patientId(publishParamBO.getPatientId())
//                .msgId(publishParamBO.getMsgId())
//                .msgType(publishParamBO.getMsgType())
//                .openId(patient.getOpenId())
//                //免责协议是否确认
//                .disclaimer(publishParamBO.getDisclaimer())
//                //处方
//                .recomId(publishParamBO.getRecomId())
//                .recomMsg(publishParamBO.getRecomMsg())
//                //病历
//                .medicalRecordId(publishParamBO.getMedicalRecordId())
//                .build()));

        return MsgPublishBO.builder().success(true).build();
    }

    @Async
    @Override
    public void publishBatchMessage(MsgPublishBatchParamBO publishBatchParamBO) {

        Doctor doctor = doctorDao.get(publishBatchParamBO.getDoctorId());
        Map<Long, Patient> patientMap = patientDao.getPatientMap(publishBatchParamBO.getPatientIds());
        if (doctor == null || MapUtils.isEmpty(patientMap)) {
            log.error("publishBatchMessage ERROR; doctor not exist or patients not exist : param={}", publishBatchParamBO);
            return;
        }

        //医生医院信息（客服消息不可使用，模板消息推送时使用）
        String hospitalName = null;
        if (doctor.getHospitalId() != null) {
            Hospital hospital = hospitalDao.get(doctor.getHospitalId());
            hospitalName = hospital != null ? hospital.getName() : doctor.getHospitalName();
        }

        FollowupMsg followupMsg = FollowupMsg.builder()
            .doctorName(String.join("-", Arrays.asList(doctor.getName(), TitleUtil.getTitle(doctor.getTitleId()),
                hospitalName)))
            .content(publishBatchParamBO.getContent()).build();
        patientMap.values().forEach(patient -> {
            followupMsg.setOpenId(patient.getOpenId());
            templateNoticeService.notice(followupMsg);
        });
    }

//    @Async
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendRecord(Long patientId, Long inquirerId, Long doctorId, Integer type, String recordId, String openId, String doctorName,
        Integer clinicFirst) throws BusinessException {
        // 记录类型, 1:病历,2:病情描述，常量抽离
        String content = emrFeginClient.getDiseaseContent(doctorId, patientId, inquirerId, type, recordId);
        InquireCaseBO caseBO = null;
        Integer msgType;
        switch (type) {
            case 1:
                msgType = PatientMsgSendParamBO.MsgType.MEDICALRECORD;
                caseBO = emrFeginClient.getInquirerCase(recordId);
                break;
            case 2:
                msgType = PatientMsgSendParamBO.MsgType.PATIENTDISEASE;
                caseBO = emrFeginClient.getInquirerDiesase(recordId);
                break;
            default:
                //TODO 非法病历类型异常
                throw new BusinessException(ExceptionCodes.HTTP_ERR);
        }

        // 切换该医生为当前咨询医生
        RedisUtil.hashOps().hset(CommonConstant.CONSULT_PATIENT_AIM, patientId.toString(), doctorId.toString());
        RedisUtil.hashOps().hset(CommonConstant.CONSULT_PATIENT_AIM_NAME, patientId.toString(), doctorName);
        RedisUtil.hashOps().hset(CommonConstant.CONSULT_PATIENT_AIM_INQUIRER, String.join("_", doctorId.toString(), patientId.toString()),
            caseBO.getInquirerId().toString());

        RedisUtil.hashOps().hset(CommonConstant.CONSULT_DISCLAIMER_ACTIVE, patientId + "_" + doctorId, Boolean.TRUE.toString());
        List<String> diagnosis = caseBO.getDiagnosis();
        if (CollUtil.isNotEmpty(diagnosis)) {
            String diagnosisStr = diagnosis.stream().collect(Collectors.joining("、"));
            RedisUtil.hashOps().hset(CommonConstant.CONSULT_PATIENT_AIM_DISEASE, patientId + "_" + doctorId, diagnosisStr);
        }
        RedisUtil.hashOps().hset(CommonConstant.CONSULT_PATIENT_AIM_DISEASE, patientId + "_" + doctorId, "病情咨询");

        if (null != clinicFirst && clinicFirst == 1) {
            // 专家名医首次咨询
            log.info("专家名医首次咨询，发送顶部提示消息。参数： openId {}", openId);
            EventUtil.publishEvent(new WxMsgEvent(openId, "", null, PatientMsgSendParamBO.MsgType.CLINICFIRSTCONSULT));
        }

        publishRecordMsg(recordId, openId, content, msgType);
//        customMsgApiService.sendSystemMsg(openId, "您的病情已发送给医生，请耐心等待医生回复，也可以继续补充问题描述~");
        if (PatientMsgSendParamBO.MsgType.MEDICALRECORD == msgType) {
            emrFeginClient.addCaseWhite(doctorId, recordId);
        }

        if (CollectionUtils.isNotEmpty(diagnosis)) {
            //更新患者诊断
            recomFeginClient.updateDiagnosis(PatientDiagnisisBO.builder()
                .doctorId(doctorId)
                .patientId(patientId)
                .inquirerId(caseBO.getInquirerId())
                .diagnosis(diagnosis)
                .build());
        }

    }

    @Override
    public MsgPublishBO publishMaMessage(MsgMaPublishParamBO publishParamBO) {
        Doctor doctor = doctorDao.get(publishParamBO.getDoctorId());
        Patient patient = patientDao.get(publishParamBO.getPatientId());
        if (patient == null || doctor == null) {
            return MsgPublishBO.builder().success(false).build();
        }
        log.info("创建小程序订阅消息事件：{}", JSONUtil.toJsonStr(publishParamBO));
        EventUtil.publishEvent(new WxMaMsgEvent(publishParamBO, WxMaMsgData
                .builder()
                .doctorId(publishParamBO.getDoctorId())
                .patientId(publishParamBO.getPatientId())
                .openId(patient.getMiniOpenId())
                .targetPage(publishParamBO.getPath())
                .doctorName(doctor.getName())
            .patientName(StrUtil.isBlank(patient.getName()) ? patient.getNickName() : patient.getName())
                .msgId(publishParamBO.getMsgId())
                .msgType(publishParamBO.getMsgType())
                .content(publishParamBO.getContent())
                //处方
                .recomId(publishParamBO.getRecomId())
                //病历
                .medicalRecordId(publishParamBO.getMedicalRecordId())
                .diseaseId(publishParamBO.getDiseaseId())
            .followUpId(publishParamBO.getFollowUpId())
                .build()));
        return MsgPublishBO.builder().success(true).build();
    }

    @Override
    public void publishBatchMaMessage(MsgMaPublishBatchParamBO publishBatchParamBO) {
        Doctor doctor = doctorDao.get(publishBatchParamBO.getDoctorId());
        Map<Long, Patient> patientMap = patientDao.getPatientMap(publishBatchParamBO.getPatientIds());
        if (doctor == null || MapUtils.isEmpty(patientMap)) {
            log.error("publishBatchMessage ERROR; doctor not exist or patients not exist : param={}", publishBatchParamBO);
            return;
        }
        InquiryRemindBO inquiryRemindBO = InquiryRemindBO.builder()
                .inquiryDoctor(doctor.getName())
                .inquiryContent("群发通知")
                .reminderContent(publishBatchParamBO.getContent())
                .promptDesc("无")
                .build();
//        inquiryRemindBO.setTargetPage("/pages/home/home");
        patientMap.values().forEach(patient -> {
            inquiryRemindBO.setOpenId(patient.getMiniOpenId());
            wxFeignClient.subscribeSendInquiryRemind(inquiryRemindBO);
        });
    }

    @Async
    @Override
    public void sendFirstFreeSession(Long patientId, Long inquirerId, Long doctorId, String openId, String doctorName) {
        // 切换该医生为当前咨询医生
        RedisUtil.hashOps().hset(CommonConstant.CONSULT_PATIENT_AIM, patientId.toString(), doctorId.toString());
        RedisUtil.hashOps().hset(CommonConstant.CONSULT_PATIENT_AIM_NAME, patientId.toString(), doctorName);
        RedisUtil.hashOps().hset(CommonConstant.CONSULT_PATIENT_AIM_INQUIRER, String.join("_", doctorId.toString(), patientId.toString()),
                inquirerId.toString());

        RedisUtil.hashOps().hset(CommonConstant.CONSULT_DISCLAIMER_ACTIVE, patientId + "_" + doctorId, Boolean.TRUE.toString());
        // 专家名医首次咨询
        log.info("患者首次绑定医生，发送顶部提示消息。参数： openId {}", openId);
        EventUtil.publishEvent(new WxMsgEvent(openId, "", null, PatientMsgSendParamBO.MsgType.CLINICFIRSTCONSULT));
    }

    @Async
    public void publishRecordMsg(String recordId, String openId, String content, Integer msgType) {
        try {
            Thread.sleep(1000);
            EventUtil.publishEvent(new WxMsgEvent(openId, content, recordId, msgType));
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.error("病历消息发送失败！");
        }

    }
}
